package org.geoscrape;

import static org.geoscrape.util.HtmlParser.getContent;

import java.io.IOException;
import java.util.HashMap;

import org.geoscrape.util.HtmlParser;
import org.geoscrape.util.UserAgentFaker;
import org.geoscrape.util.WebClient;

/**
 * A class that maintains a login/password pair and, once authenticated to the
 * site, tracks the credentials.
 * 
 */
public class Login
{
	private static final String LOGIN_STRING = "https://www.geocaching.com/login/default.aspx";

	private String userName;
	private String password;
	private String token;
	private Long id;
	private boolean authenticated = false;
	private WebClient client;

	// default date format
	private String dateFormat = null;

	private Location homeLocation;

	public Login(String userName, String password)
	{
		this.userName = userName;
		this.password = password;
	}

	/**
	 * @return the userName
	 */
	public String getUserName()
	{
		return userName;
	}

	/**
	 * @return the password
	 */
	public String getPassword()
	{
		return password;
	}

	/**
	 * @return the token
	 */
	public String getToken()
	{
		return token;
	}

	/**
	 * @return true if the Login is authenticated
	 */
	public boolean isAuthenticated()
	{
		return authenticated;
	}

	/**
	 * Attempt to authenticate
	 * 
	 * @throws IOException
	 */
	public void authenticate() throws IOException
	{
		client = new WebClient();
		client.setUserAgent(UserAgentFaker.getRandomUserAgent());
		client.goTo(LOGIN_STRING);
		String contents = client.getContentsAsString();
		HashMap<String, String> values = HtmlParser.getViewState(contents);
		values.put("__EVENTTARGET", "");
		values.put("__EVENTARGUMENT", "");
		values.put("ctl00$ContentBody$tbUsername", this.getUserName());
		values.put("ctl00$ContentBody$tbPassword", this.getPassword());
		values.put("ctl00$ContentBody$cbRememberMe", "on");
		values.put("ctl00$ContentBody$btnSignIn", "Sign In");
		client.setRequestMethod("POST");
		client.submitForm(LOGIN_STRING, values);

		token = (client.getCookies().get("ASP.NET_SessionId"));
		if (token != null)
		{
			// get the user id
			client.setRequestMethod("GET");
			client.goTo("https://www.geocaching.com/account/settings/membership");
			contents = client.getContentsAsString();
			String memberIdText = getContent("<dl class=\"membership-details\">", "</dd>", contents);
			if (memberIdText != null)
			{
				memberIdText = getContent("<dd>",  memberIdText);
				if (memberIdText != null)
				{
					memberIdText = memberIdText.replaceAll("&nbsp;", "");
					memberIdText = memberIdText.replaceAll(" ", "");
					memberIdText = memberIdText.trim();
					id = Long.parseLong(memberIdText);
					authenticated = true;
				}
			}
			// get the home location
			client.goTo("https://www.geocaching.com/account/settings/homelocation");
			contents = client.getContentsAsString();
			String homeLocationText = getContent("<div class=\"search-coordinates-wrapper\">",contents);
			if (homeLocationText != null)
			{
				homeLocationText = getContent("value=\"","\" />",homeLocationText);
				if(homeLocationText!=null)
				{
					homeLocation = new Location(homeLocationText);
				}
			}
		}
	}

	/**
	 * Get the date format used by the current user on the site.
	 * 
	 * @return the dateFormat
	 */
	public String getDateFormat()
	{
		if (dateFormat == null)
		{
			checkDateFormat();
		}
		return dateFormat;
	}

	public Location getHomeLocation()
	{
		return homeLocation;
	}

	/**
	 * Load the user account page and decode the date format.
	 * 
	 */
	private void checkDateFormat()
	{
		try
		{
			getClient().goTo("https://www.geocaching.com/myaccount/settings/preferences");
			while (getClient().getRedirectAddress() != null)
			{
				getClient().goTo(getClient().getRedirectAddress());
			}
			String contents = client.getContentsAsString();
			String df = getContent("name=\"SelectedDateFormat\"", contents);
			dateFormat = getContent("<option selected=\"selected\" value=\"","\">", df);

		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public WebClient getClient()
	{
		return client;
	}

	public void setId(Long id)
	{
		this.id = id;
	}

	public Long getId() throws IOException
	{
		return id;
	}

}
